#include "../../include/mem.h"
#include "../../include/myPrintk.h"
unsigned long MemStart; //可用的内存的起始地址
unsigned long MemSize;	//可用的大小

#define USER_MEM_START 0x1000000

void memTest(unsigned long start, unsigned long grainSize)
{
	/*本函数需要实现！！！*/
	/*功能：检测算法
			这一个函数对应实验讲解ppt中的第一大功能-内存检测。
			本函数的功能是检测从某一个地址开始的内存是否可用，具体算法就可以用ppt上说的写了读看是否一致。
	注意点两个：
	1、开始的地址要大于1M，需要做一个if判断。
	2、grainsize不能太小，也要做一个if判断
	*/

	if (start < 0x100000)
		start = 0x100000; // start from 1M
	if (grainSize < 0x100)
		grainSize = 0x100; // min step=256
	unsigned long testMemSize = 0;

	unsigned char *p = (unsigned char *)start; // start addr
	while (1)
	{
		unsigned char temp1 = 0;
		unsigned char temp2 = 0;

		// check start
		temp1 = p[0];
		temp2 = p[1];
		p[0] = 0xAA;
		p[1] = 0x55;
		if (p[0] != 0xAA || p[1] != 0x55)
		{
			break;
		}
		p[0] = 0x55;
		p[1] = 0xAA;
		if (p[0] != 0x55 || p[1] != 0xAA)
		{
			break;
		}
		p[0] = temp1;
		p[1] = temp2;

		// check end
		temp1 = p[grainSize - 2];
		temp2 = p[grainSize - 1];
		p[grainSize - 2] = 0xAA;
		p[grainSize - 1] = 0x55;
		if (p[grainSize - 2] != 0xAA || p[grainSize - 1] != 0x55)
		{
			break;
		}
		p[grainSize - 2] = 0x55;
		p[grainSize - 1] = 0xAA;
		if (p[grainSize - 2] != 0x55 || p[grainSize - 1] != 0xAA)
		{
			break;
		}
		p[grainSize - 2] = temp1;
		p[grainSize - 1] = temp2;

		// add maxuse
		testMemSize += grainSize;
		p += grainSize;
	}

	// change global value
	MemStart = start;
	MemSize = testMemSize;

	// out
	// myPrintk(0x7, "MemStart: %x  \n", start);
	// myPrintk(0x7, "MemSize:  %x  \n", MemSize);

	return;
}

extern unsigned long _end;

unsigned long kmemend;

void kMemInit(void)
{
	unsigned long _end_addr = (unsigned long)&_end;
	memTest(0x100000, 0x1000);
	// myPrintk(0x7, "_end:  %x  \n", _end_addr);
	if (MemStart <= _end_addr)
	{
		MemSize -= _end_addr - MemStart;
		MemStart = _end_addr;
	}
	if (MemSize >= USER_MEM_START - _end_addr)
		MemSize = USER_MEM_START - _end_addr;

	kMemHandler = dPartitionInit(MemStart, MemSize);
	/*myPrintk(0x7,"init kmemory like below:\n");
	dPartitionWalkByAddr(kMemHandler);
	myPrintk(0x7,"\n");*/
	return;
}

void pMemInit(void)
{
	memTest(USER_MEM_START, 0x1000);
	// myPrintk(0x7, "_end:  %x  \n", _end_addr);
	pMemHandler = dPartitionInit(MemStart, MemSize);
	/*myPrintk(0x7,"init pmemory like below:\n");
	dPartitionWalkByAddr(pMemHandler);
	myPrintk(0x7,"\n");*/
	return;
}
